#pragma once
#include "..\dxstdafx.h"
#include "IndexBuffer.h"
#include <vector>

namespace ds {

template <class T>
class DynamicVertexBuffer {

typedef std::vector<T*> Vertices;

public:
	DynamicVertexBuffer(D3DPRIMITIVETYPE primitiveType,IDirect3DVertexDeclaration9* vertexDeclaration,int vertexSize,int maxVertices);
	~DynamicVertexBuffer();
	void addVertex(T* v);
	void clear();
	void update(DWORD flags = D3DLOCK_DISCARD);

	void preRendering();
	void render(int numPrimitives);
	void postRendering();
private:
	Vertices m_Vertices;
	int m_MaxVertices;
	IDirect3DVertexDeclaration9* m_VertexDeclaration;
	LPDIRECT3DVERTEXBUFFER9 vertexBuffer;
    IndexBuffer* indexBuffer;
    UINT m_numVertices;
    int m_vertexSize;
	D3DPRIMITIVETYPE m_primitiveType;
};

template<class T> 
DynamicVertexBuffer<T>::DynamicVertexBuffer(D3DPRIMITIVETYPE primitiveType,IDirect3DVertexDeclaration9* vertexDeclaration,int vertexSize,int maxVertices) 
	: m_VertexDeclaration(vertexDeclaration) , m_vertexSize(vertexSize) , m_primitiveType(primitiveType) , m_MaxVertices(maxVertices) {
		
	IDirect3DDevice9 * pDevice = gEngine->getDevice();
	D3DPOOL pool = D3DPOOL_DEFAULT; 
	DWORD usage = D3DUSAGE_WRITEONLY | D3DUSAGE_DYNAMIC; 		
	LOG(logINFO) << "creating new dynamic vertext buffer - size: " << m_MaxVertices;
	HR(pDevice->CreateVertexBuffer( m_MaxVertices * vertexSize,usage,0 ,pool, &vertexBuffer, NULL ));
	indexBuffer = 0;
}

template<class T> 
DynamicVertexBuffer<T>::~DynamicVertexBuffer() {
	if( vertexBuffer ) { 
		vertexBuffer->Release(); 
		vertexBuffer = NULL; 
	} 
}

template<class T> 
void DynamicVertexBuffer<T>::addVertex(T* v) {
	m_Vertices.push_back(v);
}

template<class T> 
void DynamicVertexBuffer<T>::clear() {
	for ( size_t i = 0 ; i < m_Vertices.size(); ++i ) {
		delete m_Vertices[i];
	}
	m_Vertices.clear();
}

template<class T> 
void DynamicVertexBuffer<T>::update(DWORD flags) {
	int total = m_Vertices.size();	
	if ( total > 0 ) {		
		T* pVertices;
		HR(vertexBuffer->Lock( 0, 0, ( void** )&pVertices, 0 ));	
		for ( size_t i = 0; i < total; ++i ) {		
			m_Vertices[i]->set(pVertices);
			pVertices++;
		}
		HR(vertexBuffer->Unlock());
	}
	m_numVertices = total;
}

template<class T> 
void DynamicVertexBuffer<T>::preRendering() {
	if ( m_numVertices > 0 ) {
		IDirect3DDevice9 * pDevice = gEngine->getDevice();
		update();
		if ( indexBuffer != 0 ) {
			indexBuffer->init();
		}
		pDevice->SetStreamSource( 0, vertexBuffer, 0, m_vertexSize ); 
		pDevice->SetVertexDeclaration(m_VertexDeclaration);
	}
}

template<class T> 
void DynamicVertexBuffer<T>::render(int numPrimitives) {
	if ( m_numVertices > 0 ) {
		IDirect3DDevice9 * pDevice = gEngine->getDevice();
		if ( indexBuffer ) {
			HR(pDevice->SetIndices( indexBuffer->getIndexBuffer() )); 
			HR(pDevice->DrawIndexedPrimitive( m_primitiveType, 0, 0, m_numVertices, 0, numPrimitives ));
			gEngine->getDrawCounter()->addIndices(indexBuffer->getSize());
			gEngine->getDrawCounter()->addPrimitives(m_numVertices);
		} 
		else {
			HR(pDevice->DrawPrimitive(m_primitiveType,0,numPrimitives));
			gEngine->getDrawCounter()->addPrimitives(m_numVertices);
		}		
	}
}

template<class T> 
void DynamicVertexBuffer<T>::postRendering() {
}

};

